home *** CD-ROM | disk | FTP | other *** search
/ X User Tools / X User Tools (O'Reilly and Associates)(1994).ISO / sources / xbmbrows / xbmbro31.z / xbmbro31 / xbmbrowser3.1 / user-menu.c < prev    next >
C/C++ Source or Header  |  1993-08-05  |  14KB  |  547 lines

  1. /*
  2. *****************************************************************************
  3. ** xbmbrowser version 3.1  (c) Copyright Ashley Roll, 1992.
  4. ** FILE: user-menu.c
  5. **
  6. ** xbmbrowser is Public Domain. However it, and all the code still belong to me.
  7. ** I do, however grant permission for you to freely copy and distribute it on 
  8. ** the condition that this and all other copyright notices remain unchanged in 
  9. ** all distributions.
  10. **
  11. ** This software comes with NO warranty whatsoever. I therefore take no
  12. ** responsibility for any damages, losses or problems that the program may 
  13. ** cause.
  14. *****************************************************************************
  15. */
  16.  
  17. #define USER_MENU_C_FILE
  18. #include "xbmbrowser.h"
  19. #include "user-menu.h"
  20. #include <pwd.h>
  21.  
  22. static char trans[] =
  23.   "<Key>Return:  Ok() \n\
  24.    Ctrl<Key>M:   Ok() ";
  25.  
  26. /* 
  27.  * Macro to test characters
  28.  */
  29. #define NOT_VALID(x) (x != '!') && (x != '\"')
  30. #define IS_QUOTE(x) (x == '\"')
  31. #define IS_MACRO(x) (x == 'b' || x == 'B' || x == 'u' || x == 'n' || x == 'd') 
  32. #define IS_SPACE(x) (x == ' ' || x == '\t' )
  33.  
  34. /*
  35.  * data structure that is given to each menu entry to return as clientdata.
  36.  */
  37.  
  38. typedef struct _menuInfo {
  39.   char menuName[100];
  40.   char command[256];
  41.   char queryLabel[100];
  42.   unsigned rescan:1;
  43.   unsigned useQuery:1;
  44.   unsigned needInput:1;
  45.   unsigned useDefText:1;
  46. } MenuInfo;
  47.  
  48. /*
  49.  * global pointer to hold the current MenuInfo so that
  50.  * all the procedures know about it
  51.  */
  52. Widget query,DWidget;
  53. MenuInfo *G_Info;
  54. int dialogsMade = 0;
  55. char dialogString[255];
  56.  
  57. void HandleMenu();
  58. MenuInfo *ParseNextLine();
  59. int parseCommand();
  60. void Cancel();
  61. void Ok();
  62. void setup_dialog();
  63. void executeCommand();
  64.  
  65. /*
  66. ** expand a tilder in situ
  67. ** This was sent to me by:
  68. _______________________________________________________________________________
  69. Chris McDonald.            _--_|\
  70.                           /      \
  71.                           X_.--._/
  72.                                 v
  73. Department of Computer Science,   AARNet: chris@budgie.cs.uwa.edu.au
  74. University of Western Australia,  FTP:    bilby.cs.uwa.edu.au,  130.95.1.11
  75. Crawley, Western Australia, 6009. SCUD:   (31.97 +/-10% S, 115.81 +/-10% E)
  76. PHONE:       +61 9 380 2533       FAX:    +61 9 380 1089
  77. **
  78. ** and I have modified it slightly
  79. */
  80. void expand_tilder(text)                /* expand in-situ in twiddle */
  81. char *text;
  82. {
  83.     static char buf[255];
  84.     char *s, *t, *t1;
  85.     struct passwd *p, *getpwnam();
  86.  
  87.     s = text;
  88.     s++;                                        /* skip leading twiddle */
  89.     t = buf;
  90.     while (*s && *s != '/')
  91.         *t++ = *s++;
  92.     *t = '\0';
  93.     if(*buf && (p = getpwnam(buf)) == '\0')
  94.         return;
  95.     t1 = *buf ? p->pw_dir : (char *) getenv("HOME");
  96.     t = buf;
  97.     while( *t++ = *t1++ );                      /* buf <- home_dir */
  98.     t--;
  99.     while( *t++ = *s++ );                       /* buf += rest_of_a */
  100.     t  = text;
  101.     t1 = buf;
  102.     while( *t++ = *t1++ );                      /* s   <- buf */
  103. }
  104.  
  105. /*
  106. ** Create a new menu - and put a line under the lable
  107. */
  108. Widget MakeMenu(parent,name,label)
  109. Widget parent;
  110. char *name,*label;
  111. {
  112. Widget w;
  113.  
  114.  
  115.    w = XtVaCreatePopupShell(name,simpleMenuWidgetClass,parent,
  116.                      XtNlabel,(XtArgVal)label,NULL);
  117.  
  118.    if (label != NULL)
  119.    (void) XtVaCreateManagedWidget("line",smeLineObjectClass,w,NULL);
  120.  
  121. return(w);
  122. }
  123.  
  124. /*
  125. ** add an smeBSBObjectClass object to a menu (widget)
  126. ** callback is the procedure that it calls or NULL
  127. */
  128. Widget AddMenuItem(menu,label,callback,cbdata,sensitive)
  129. Widget menu;
  130. char *label;
  131. XtCallbackProc callback;
  132. XtPointer cbdata;
  133. int sensitive;
  134. {
  135. Widget w;
  136.  
  137.   w = XtVaCreateManagedWidget(
  138.              label,smeBSBObjectClass,menu,
  139.              XtNlabel,(XtArgVal)label,XtNjustify,XtJustifyCenter,NULL);
  140.  
  141.   if(!sensitive)
  142.     XtVaSetValues(w,XtNsensitive,(XtArgVal)False,NULL);
  143.  
  144.   if(callback != NULL)
  145.   XtAddCallback( w, "callback",callback, cbdata);
  146.  
  147. return (w);
  148. }
  149.  
  150. /*
  151.  * create the menu from the given file, give it the name in name and 
  152.  * make it as the child of parent 
  153.  */
  154. Widget Create_user_menu(parent,name,file)
  155. Widget parent;
  156. char *name,*file;
  157. {
  158. Widget Menu;
  159. MenuInfo *CLineInfo;
  160. FILE *fp;
  161.  
  162.   /* open the menu description file */
  163.   if((fp=fopen(file,"r")) == NULL) {
  164.     fprintf(stderr,"Cannot open Menu Description file: %s\n",file);
  165.     exit(1);
  166.   }
  167.  
  168.   /* make the menu */
  169.   Menu = MakeMenu(parent,name,NULL);
  170.  
  171.   /* parse the one line if the file at a time , create a new MenuInfo struct 
  172.   for each line. then fill in the information and add the menu item */
  173.   while(CLineInfo = ParseNextLine(fp)) {
  174.     AddMenuItem(Menu,CLineInfo->menuName,HandleMenu,(XtPointer)CLineInfo,1);
  175.   } 
  176.  
  177.   /* close the file */
  178.   fclose(fp);
  179.  
  180.   if(!dialogsMade) setup_dialog();
  181.  
  182.   return Menu;
  183. }
  184.  
  185.  
  186. MenuInfo *ParseNextLine(fp)
  187. FILE *fp;
  188. {
  189. MenuInfo *info;
  190. char line[256];
  191. char *s,*d;
  192. char menuName[100];
  193. char command[256];
  194. char queryLabel[100];
  195. unsigned needInput = 0, useDefText = 0;
  196. static int linenum = 0;
  197.  
  198.  
  199.   /* read in a line at a time until find one that is not a comment or a blank 
  200.      If the end of file comes up then return NULL */
  201. getline:  
  202.   fgets(line,256,fp);
  203.   linenum++;
  204.   while(NOT_VALID(line[0]) && !feof(fp)) {
  205.     fgets(line,256,fp); 
  206.     linenum++;
  207.   }
  208.   if(feof(fp)) return NULL;
  209.   
  210.   /* get the Menu name string */
  211.     s = line;
  212.  
  213.     /* find the first quote */
  214.       while(! IS_QUOTE(*s) && *s != '\0') 
  215.          s++;
  216.  
  217.     /* copy the string into menuName */
  218.       d = menuName;
  219.       s++;
  220.       while(! IS_QUOTE(*s) && *s != '\0')
  221.         *d++ = *s++;
  222.       
  223.       *d = '\0';
  224.  
  225.       if(*s == '\0') {
  226.         /* line incomplete - print and error and get new line */
  227.         fprintf(stderr,"Error in menu description at line %d\n",linenum);
  228.         fprintf(stderr," - failed to find the menu name.\n");
  229.         goto getline;
  230.       }
  231.   s++; 
  232.   /* get the command string */
  233.     /* find the opening quote */
  234.       while(! IS_QUOTE(*s) && *s != '\0') 
  235.          s++;
  236.   
  237.     /* copy the string into command */ 
  238.       d = command;
  239.       s++;
  240.       while(! IS_QUOTE(*s) && *s != '\0') 
  241.         *d++ = *s++; 
  242.      
  243.       *d = '\0';
  244.  
  245.       if(*s == '\0') {
  246.         /* line incomplete - print and error and get new line */      
  247.         fprintf(stderr,"Error in menu description at line %d\n",linenum);
  248.         fprintf(stderr," - failed to find the command.\n");
  249.         goto getline;
  250.       }
  251.  
  252.   s++;
  253.   /* get the query string */
  254.     /* find the opening quote */
  255.       while(! IS_QUOTE(*s) && *s != '\0') 
  256.          s++;
  257.   
  258.     /* copy the string into queryLabel */ 
  259.       d = queryLabel;
  260.       s++;
  261.       while(! IS_QUOTE(*s) && *s != '\0') 
  262.         *d++ = *s++; 
  263.      
  264.       *d = '\0';
  265.  
  266.       if(*s == '\0') {
  267.         /* line incomplete - print and error and get new line */
  268.         fprintf(stderr,"Error in menu description at line %d\n",linenum);
  269.         fprintf(stderr," - failed to find the query label.\n");
  270.         goto getline;
  271.       }
  272.  
  273.   s++;
  274.   /* if all are correct allocate a MenuInfo struct and fill it in,
  275.      otherwise go back and get another line */
  276.  
  277.   if(!parseCommand(command,&needInput,&useDefText)) {
  278.     fprintf(stderr,"Error in menu description at line %d\n",linenum);
  279.     fprintf(stderr," - bad command.\n");
  280.     goto getline;
  281.   } else {
  282.     info = (MenuInfo *) malloc(sizeof(MenuInfo));
  283.     strcpy(info->menuName,menuName);
  284.     strcpy(info->command,command);
  285.     strcpy(info->queryLabel,queryLabel);
  286.  
  287.     info->rescan = (line[0] != '!');
  288.     info->useQuery = (queryLabel[0] != '\0');
  289.     info->needInput = needInput; 
  290.     info->useDefText = useDefText;
  291.  
  292.     /* check that if we needInput that we are useQuery */
  293.     if(info->needInput && !info->useQuery) {
  294.       fprintf(stderr,"Error in menu description at line %d\n",linenum);
  295.       fprintf(stderr," - need input but no query.\n");
  296.       free(info);
  297.       goto getline;
  298.     }
  299.   }
  300.  
  301.   /* return the MenuInfo */
  302.   return info;
  303. }
  304.  
  305. int parseCommand(command,needInput,useDefText)
  306. char *command;
  307. unsigned *needInput,*useDefText;
  308. {
  309. char temp[256], *s, *d;
  310. char t_expand_temp[256],*t;
  311. int i;
  312.  
  313.   /* make a copy of the command */
  314.   strcpy(temp,command); 
  315.   s = temp;
  316.   d = command;
  317.   *needInput = *useDefText = 0;
  318.  
  319.   while(*s != '\0') {
  320.     *d++ = *s;
  321.     if(*s == '%') { /* is a place holder (macro) */
  322.       if(! IS_MACRO(*(s+1))) {
  323.         fprintf(stderr,"Error in command - bad place holder.\n");
  324.         return 0; 
  325.       } 
  326.       if(*(s+1) == 'u') {
  327.         *needInput = 1; 
  328.         *useDefText = 1;
  329.       } 
  330.       if(*(s+1) == 'n') {
  331.         *needInput = 1;
  332.       }
  333.     }
  334.  
  335.     if(*s == '~') { /* expand the tilder */
  336.       /* empty the temp string */
  337.       for(i=0;i<256;t_expand_temp[i++] = '\0');
  338.  
  339.       /* copy string into t_expand_temp */
  340.       t = t_expand_temp;
  341.       while((! IS_SPACE(*s)) && *s != '%' && *s != '\0')
  342.         *t++ = *s++;
  343.  
  344.       *t = '\0';
  345.       s--;
  346.       expand_tilder(t_expand_temp);
  347.  
  348.       /* copy it back into *d */
  349.       t = t_expand_temp;
  350.       d--;
  351.       while(*d++ = *t++);
  352.       d--;  /* go back over the null */
  353.     }
  354.  
  355.     s++;
  356.   }
  357.   *d = '\0';
  358.  
  359.   return 1; 
  360. }
  361.  
  362. /* 
  363. ** from the bitmap_info pointer to the current bitmaps information line
  364. ** extract the bitmaps file name   --- Anthony Thyssen  24/7/93
  365. */
  366. char *get_bitmap_name()
  367. {
  368.   static char name[256];
  369.   int length;
  370.  
  371.   assert(bitmap_info != NULL);
  372.   assert(bitmap_info[0] == '\"');
  373.  
  374.   length = rindex(bitmap_info, '\"') - bitmap_info;
  375.   length -= 1;    
  376.   strncpy(name, bitmap_info+1, length);
  377.   name[length] = '\0';
  378.   
  379.   return name;
  380. }
  381.  
  382.  
  383. /*
  384.  * Handle the executing of commands. Called by the menu.
  385.  */
  386. void HandleMenu(w,client_data,call_data )
  387. Widget w;
  388. XtPointer client_data,call_data;
  389. {
  390.   Position    x, y;
  391.  
  392.   G_Info = (MenuInfo *)client_data;
  393.  
  394.   /* Check if we need the dialog box */
  395.   if(G_Info->useQuery) {
  396.     /* setup the dialog box */
  397.       /* set the label */
  398.       XtVaSetValues(DWidget,XtNlabel,(XtArgVal)G_Info->queryLabel,NULL);        
  399.       /* check if we need the text widget */
  400.       if(G_Info->needInput) {
  401.         /* activate the text widget */
  402.  
  403.         /* set the bitmap name as the default string if useDefText */
  404.         if(G_Info->useDefText) 
  405.           XtVaSetValues(DWidget,XtNvalue,(XtArgVal)get_bitmap_name(),NULL);
  406.         else
  407.           XtVaSetValues(DWidget,XtNvalue,(XtArgVal)"",NULL);
  408.  
  409.         XtVaSetValues(XtNameToWidget(DWidget,"value"),
  410.                       XtNresizable,(XtArgVal)True,
  411.                       NULL);
  412.  
  413.         XtOverrideTranslations(XtNameToWidget (DWidget, "value"),
  414.               XtParseTranslationTable(trans));
  415.  
  416.       } else {
  417.         /* deactivate the text widget */
  418.         XtVaSetValues(DWidget,XtNvalue,(XtArgVal)NULL,NULL);
  419.       }
  420.  
  421.       /* check the position and move the window to the same relative place */
  422.       XtVaGetValues(toplevel,XtNx,&x,XtNy,&y,NULL);
  423.       XtVaSetValues(query,XtNx,(XtArgVal)x+50,XtNy,(XtArgVal)y+100,NULL);
  424.  
  425.       /* popup the dialog widget */
  426.       XtPopup(query,XtGrabExclusive);
  427.  
  428.   } else {
  429.     /* execute the command */
  430.     executeCommand();
  431.   }
  432.  
  433. }
  434.  
  435.  
  436. /*
  437. ** setup the dialog window
  438. */
  439. void setup_dialog()
  440. {
  441.   Position x,y;
  442.  
  443.   XtVaGetValues(toplevel,XtNx,&x,XtNy,&y,NULL);
  444.  
  445.   query = XtVaCreatePopupShell("Query",transientShellWidgetClass,mainpw,
  446.                        XtNx,(XtArgVal)x+50,XtNy,(XtArgVal)y+100,NULL);
  447.  
  448.   DWidget = XtVaCreateManagedWidget("GetName",dialogWidgetClass,query,
  449.                        XtNvalue,(XtArgVal)"",
  450.                        NULL);
  451.   XtOverrideTranslations(XtNameToWidget (DWidget, "value"),
  452.               XtParseTranslationTable(trans));
  453.  
  454.   XawDialogAddButton(DWidget,"Ok",Ok,NULL);
  455.   XawDialogAddButton(DWidget,"Cancel",Cancel,NULL);
  456.  
  457. }
  458.  
  459.  
  460. /*
  461. ** callback for the OK button in the rename and copy requesters
  462. */
  463. void Ok(w,client_data,call_data )
  464. Widget w;
  465. XtPointer client_data,call_data;
  466. {
  467. int i;
  468.  
  469.   if(G_Info->needInput) {
  470.     strcpy(dialogString, XawDialogGetValueString(DWidget));
  471.  
  472.     /* search for the first non-space char */
  473.     i = 0;
  474.     while(isspace(dialogString[i])) i++;
  475.  
  476.     if(dialogString[i] == '~') expand_tilder(&dialogString[i]);
  477.   }
  478.  
  479.   XtPopdown(query);
  480.  
  481.   executeCommand();
  482. }
  483.  
  484. /*
  485. ** callback for the cancel button
  486. */
  487. void Cancel(w,client_data,call_data )
  488. Widget w;
  489. XtPointer client_data,call_data;
  490. {
  491.   XtPopdown(query);
  492. }
  493.  
  494. /* 
  495.  * Use the information in the global variables to execute the command that the
  496.  * user enter into the menu definition
  497.  */
  498. void executeCommand()
  499. {
  500. char cmd[256],*s,*d,*t;
  501.  
  502.   /* copy the command from G_Info->command to cmd, expanding all % things. */
  503.  
  504.   s = G_Info->command;
  505.   d = cmd;
  506.  
  507.   while(*s != '\0') {
  508.     if(*s == '%') { /* is a place holder (macro) */
  509.       /* expand macro */  
  510.       s++;
  511.       switch(*s) {
  512.         case'B': /* Current bitmap name (with full path) */
  513.                  /* copy the directory */
  514.                  for(t = directory; *t != '\0'; *d++ = *t++);
  515.                  *d++ = '/';
  516.                  /* fall-through */
  517.  
  518.         case'b': /* Current bitmap name (no path) */
  519.                  for(t = get_bitmap_name(); *t != '\0'; *d++ = *t++);
  520.                  break;
  521.  
  522.         case'u': /* Users input string */
  523.         case'n': /* Users input string - no default val */
  524.                  for(t = dialogString; *t != '\0'; *d++ = *t++);
  525.                  break;
  526.  
  527.         case'd': /* Current Directory */
  528.                  for(t = directory; *t != '\0'; *d++ = *t++);
  529.                  break;
  530.       }
  531.  
  532.     } else {
  533.       *d++ = *s;   /* just copy char */
  534.     }
  535.  
  536.     s++;
  537.   }
  538.   *d = '\0';
  539.  
  540.   /* do the command */
  541.   system(cmd);
  542.  
  543.   /* re-setup the bitmaps if the flag is set */
  544.   if(G_Info->rescan) rescan_bitmaps();
  545.  
  546. }
  547.